
#ifndef Q3_VM
#include "cg_local.h"
#include "cgame_BOTS.h"
#include "BOTS_HUD.h"
#endif

// Maintains states and tracks changes
void updateData(stData_t *s, int value) {
	if (value != s->iData) {
		s->iData		= value;
		s->bModified	= qtrue;
		s->iTime		= cg.time;
	}
	else {
		s->bModified	= qfalse;
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

vec4_t *BOTS_HUD_getTeamColor(int iTeam) {
	static vec4_t colors[3] = {
		{ 0.5,0.5,0.5,0.33 },	// Grey, for "others"
		{ 1,0,0,0.2 },			// Red
		{ 0,0,1,0.2 }, //{ 0,0,1,0.4 },	// Blue
	};

	return ((iTeam>0)&&(iTeam<3))?&colors[iTeam]:&colors[0];
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Kludges

// WTF! Why my *nix made tga are painted with bottom/top inverted?
void myCG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
	CG_AdjustFrom640( &x, &y, &width, &height );
	trap_R_DrawStretchPic( x, y, width, height, 0, 1, 1, 0, hShader );
}

// Little helper
void BOTS_HUD_drawReadySignCentered(int x, int y, int totalwidth) {
	CG_DrawPic( x + ((totalwidth)-BOTS_HUD_ICON_SIZE)*0.5f, y, BOTS_HUD_ICON_SIZE, BOTS_HUD_ICON_SIZE, cgs.media.botsHUDiconsOther[reserved4]);
}
void BOTS_HUD_drawKeySignCentered(int x, int y, int totalwidth,int bump) {
	CG_DrawPic( x - bump + ((totalwidth)-BOTS_HUD_ICON_SIZE)*0.5f, y - bump , BOTS_HUD_ICON_SIZE + 2*bump, BOTS_HUD_ICON_SIZE + 2*bump, cgs.media.botsHUDiconsOther[reserved5]);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Widgets
float BOTS_HUD_drawIcon(float y, int iTeam, qhandle_t shaderLabel, qhandle_t shaderIcon, qboolean bKludge, qboolean bBlink) {
	vec4_t *tcolor = BOTS_HUD_getTeamColor(iTeam);
	const int
		// iconnudge	= 4,
		totalheight = BOTS_HUD_ICON_SIZE;
	const int	
		x	= 640 - BOTS_HUD_PANEL_WIDTH - (2*BOTS_HUD_PANEL_MARGIN),
		w	= BOTS_HUD_PANEL_WIDTH + 2*BOTS_HUD_PANEL_MARGIN;

	// Background
	CG_FillRect( x, y, w, totalheight, (*tcolor) );

	// The switch icon
	if (bBlink) {
		vec4_t color;

		color[0] = color[1] = color[2] = 1;
		color[3] = (cg.time%150)/150.0f;
		trap_R_SetColor(color);
	}
	// Argh
	if (bKludge)
		myCG_DrawPic(x, y, BOTS_HUD_ICON_SIZE,BOTS_HUD_ICON_SIZE, shaderIcon);
	else
		CG_DrawPic(x, y, BOTS_HUD_ICON_SIZE,BOTS_HUD_ICON_SIZE, shaderIcon);
	if (bBlink)
		trap_R_SetColor(NULL);
	// Label it
	myCG_DrawPic(x + BOTS_HUD_ICON_SIZE, y, w - BOTS_HUD_ICON_SIZE, BOTS_HUD_ICON_SIZE, shaderLabel);


	y += totalheight + BOTS_HUD_PANEL_MARGIN;
	return y;
}

// Label + on/off icon
float BOTS_HUD_drawSwitch(float y, int iTeam, stData_t *s, qhandle_t shader) {
	vec4_t *tcolor = BOTS_HUD_getTeamColor(iTeam);
	const int
		iconnudge	= 2,
		totalheight = BOTS_HUD_ICON_SIZE,
		iBumpDuration = 200;
	int	
		x	= 640 - BOTS_HUD_PANEL_WIDTH - (2*BOTS_HUD_PANEL_MARGIN),
		w	= BOTS_HUD_PANEL_WIDTH + 2*BOTS_HUD_PANEL_MARGIN,
		bump= cg.time - s->iTime;

	// Background
	CG_FillRect( x, y, w, totalheight, (*tcolor) );

	x -= iconnudge;
	w += iconnudge - BOTS_HUD_ICON_SIZE;
	// The switch icon
	CG_DrawPic(x, y, BOTS_HUD_ICON_SIZE,BOTS_HUD_ICON_SIZE, 
		s->iData?cgs.media.botsHUDiconsTeam[1][iTeam-1]:cgs.media.botsHUDiconsTeam[0][iTeam-1]);

	// Zoom it for a while on change
	if (bump < iBumpDuration) {
		bump = (w/8) * (1.0f - ((float)bump/(float)iBumpDuration));
	}
	else bump = 0;

	// Label it
	x += BOTS_HUD_ICON_SIZE - 2;
	myCG_DrawPic(x - bump , y - bump,
				 w + (2*bump), BOTS_HUD_ICON_SIZE + (2*bump), shader);


	y += totalheight + BOTS_HUD_PANEL_MARGIN;
	return y;
}

float BOTS_HUD_drawWeaponMode(float y, int iTeam, stData_t *s,qhandle_t shader) {
	vec4_t *tcolor = BOTS_HUD_getTeamColor(iTeam);
	const int
		totalheight = BOTS_HUD_ICON_SIZE,
		x = 640 - BOTS_HUD_PANEL_WIDTH - (2*BOTS_HUD_PANEL_MARGIN),
		iBumpDuration = 200;
	int				bump;
	static stData_t	*old = NULL; // Hack, sweet hack


	// Kludge!
	if (s != old) {
		s->iTime = cg.time;
		old = s;
	}

	// Background
	CG_FillRect( x, y, BOTS_HUD_PANEL_WIDTH + 2*BOTS_HUD_PANEL_MARGIN, totalheight, (*tcolor) );
	// Box around 
	CG_DrawPic( x, y, BOTS_HUD_PANEL_WIDTH + (2*BOTS_HUD_PANEL_MARGIN), BOTS_HUD_ICON_SIZE, cgs.media.botsHUDiconsTeam[4][iTeam-1]);

	// Zoom it for a while on change
	bump = cg.time - s->iTime;
	if (bump < iBumpDuration) {
		bump = (BOTS_HUD_ICON_SIZE/2) * (1.0f - ((float)bump/(float)iBumpDuration));
	}
	else bump = 0;

	// Draw the mode
	myCG_DrawPic( x+BOTS_HUD_PANEL_MARGIN - bump, y - bump, 
		BOTS_HUD_PANEL_WIDTH+(2*bump), BOTS_HUD_ICON_SIZE+(2*bump), shader);

	y += BOTS_HUD_ICON_SIZE+BOTS_HUD_PANEL_MARGIN;
	return y;
}


// Format and draws centered numbers
int BOTS_HUD_drawNumber(int x, int y, int w, int h, int iNumber, int iMaxChar) {
	static	char sBuf[256],sFormat[256];
	char	*ch = sBuf;
	vec4_t	color = { 0,0,0,1 };
	int		len,x1;

	Com_sprintf(sFormat,256,"%%%ii",iMaxChar);
	Com_sprintf(sBuf,256,sFormat,iNumber);
	len = strlen(sBuf);
	if (len>iMaxChar) {
		int i;


		for (i=0; i < iMaxChar; i++)
			sBuf[i] = '-';
		sBuf[iMaxChar] = '\0';
		len = 3;
	}

	// Tweaks
	x1 = x - 1;
	h -= 1; 
	while (*ch) {
		if (*ch != ' ') {
			// Shadow
			trap_R_SetColor(color);
			CG_DrawChar(x1+2,y+2,w,h,*ch);
			trap_R_SetColor(NULL);
			// Number
			CG_DrawChar(x1,y,w,h,*ch);
			x1 += w;
		}
		else
			// Centering...
			x1 += w/2;

		ch++;
	}

	//return x+1;
	return x+(iMaxChar*w);
}

float BOTS_HUD_drawTimer(float y, int iTeam, stData_t *s,qhandle_t shader) {
	vec4_t *tcolor = BOTS_HUD_getTeamColor(iTeam);
	const int
		totalheight = BOTS_HUD_ICON_SIZE,
		totalwidth	= BOTS_HUD_PANEL_WIDTH + 2*BOTS_HUD_PANEL_MARGIN,
		slotwidth	= 8;
	int 
		x = 640 - totalwidth,
		iTime = s->iData;


	// Background
	CG_FillRect( x, y, totalwidth, totalheight, (*tcolor) );

	// Either draw a ready sign or the time in seconds
	if (iTime <= 0) {
		const int iBumpDuration = 300;
		int bump = cg.time - s->iTime;

		// Paint it from yellow to white
		if (bump < iBumpDuration) {
			vec4_t color;

			color[0] = 1;
			color[1] = 1;
			color[2] = (float) bump/(float) iBumpDuration;
			color[3] = 1;
			trap_R_SetColor( color );
		}
		// myCG_DrawPic( x, y, slotwidth*3, BOTS_HUD_ICON_SIZE, cgs.media.botsHUDiconsOther[generic_ready]);
		BOTS_HUD_drawReadySignCentered(x,y,slotwidth*3);
		trap_R_SetColor( NULL );
		x += slotwidth*3;
	}
	else
		x = BOTS_HUD_drawNumber(x,y,slotwidth,BOTS_HUD_ICON_SIZE,iTime,3);

	// A label on what's left
	myCG_DrawPic( x, y, 640 -x, BOTS_HUD_ICON_SIZE, shader);

	y += BOTS_HUD_ICON_SIZE+BOTS_HUD_PANEL_MARGIN;
	return y;
}

// Almost the same as the timer function above
float BOTS_HUD_drawKey(float y, int iTeam, stData_t *s,qhandle_t shader) {
	vec4_t *tcolor = BOTS_HUD_getTeamColor(iTeam);
	const int
		totalheight = BOTS_HUD_ICON_SIZE,
		totalwidth	= BOTS_HUD_PANEL_WIDTH + 2*BOTS_HUD_PANEL_MARGIN,
		slotwidth	= 8,
		fieldlen	= 4;

	int 
		x = 640 - totalwidth,
		iDist = s->iData;


	// Background
	CG_FillRect( x, y, totalwidth, totalheight, (*tcolor) );

	// Either blink something or draw the distance
	if (iDist <= 0) {
		vec4_t color;
		const int iBumpDuration = 250;
		int bump = cg.time - s->iTime;

		// Paint it from yellow to white
		color[0] = 1;
		color[1] = 1;
		color[2] = (float) (bump%iBumpDuration)/(float) iBumpDuration;
		color[3] = 1;
		trap_R_SetColor( color );

		// Make it grow on pickup (first time)
		if (bump < iBumpDuration)
			bump /= (iBumpDuration/10);
		else
			bump = 0;

		BOTS_HUD_drawKeySignCentered(x,y,slotwidth*fieldlen,bump);
		trap_R_SetColor( NULL );
		x += slotwidth*fieldlen;
	}
	else
		x = BOTS_HUD_drawNumber(x,y,slotwidth,BOTS_HUD_ICON_SIZE,iDist,fieldlen);

	// A label on what's left
	myCG_DrawPic( x, y, 640 -x, BOTS_HUD_ICON_SIZE, shader);

	y += BOTS_HUD_ICON_SIZE+BOTS_HUD_PANEL_MARGIN;
	return y;
}

float BOTS_HUD_drawLaser(float y, int iTeam, stData_t *laserS,stData_t *laserT, qboolean bPulse) {
	vec4_t *tcolor = BOTS_HUD_getTeamColor(iTeam);
	const int
		totalheight = BOTS_HUD_ICON_SIZE,
		totalwidth	= BOTS_HUD_PANEL_WIDTH + 2*BOTS_HUD_PANEL_MARGIN,
		slotwidth	= 8;
	int 
		x = 640 - totalwidth,
		iTime = laserT->iData;
	static int top = 0;	// For some transient effect

	eHUD_ICONS_OTHER eSign = reserved0;

	
	// Background
	CG_FillRect( x, y, totalwidth, totalheight, (*tcolor) );

	if (!laserS->iData) {
		// Avoid annoying flickering
		if (!bPulse) {
			if ((iTime == 0) && (top == 0))
				top = cg.time; // Start the counter now!
			
			if (iTime >= 0) {
				const int iBumpDuration = 300;
				int bump = cg.time - top;
				
				// Play with the opacity
				if (bump < iBumpDuration) {
					vec4_t color;
					
					color[0] = 1;
					color[1] = 1;
					color[2] = 1;
					color[3] = (float) bump/(float) iBumpDuration;;
					trap_R_SetColor( color );
				}
				// Ready
				// myCG_DrawPic( x, y, slotwidth*3, BOTS_HUD_ICON_SIZE, cgs.media.botsHUDiconsOther[generic_ready]);
				BOTS_HUD_drawReadySignCentered(x,y,slotwidth*3);
				trap_R_SetColor( NULL );
				x += slotwidth*3;
				goto quickexit;	
			}
		}
		// Cooling
		eSign = reserved3; // Flake
		top = 0;
	}
	else {
		eSign = reserved2; // Lightbulb
		iTime = iTime;
		top = 0;
	}

	// Half of the panel for a sign, half for numbers
	x = BOTS_HUD_drawNumber(x,y,slotwidth,BOTS_HUD_ICON_SIZE,abs(iTime),2); // Offset it a bit for cooling time
	CG_DrawPic( x, y, slotwidth, BOTS_HUD_ICON_SIZE, cgs.media.botsHUDiconsOther[eSign]);
	x += slotwidth;
quickexit:
	myCG_DrawPic( x, y, 640-x, BOTS_HUD_ICON_SIZE, cgs.media.botsHUDiconsOther[bodyguard_laser]);
	y += totalheight + BOTS_HUD_PANEL_MARGIN;
	return y;
}


// Draw the class name + chevrons for levels
float BOTS_HUD_drawClassText(float y, int iClass, int iLevel, int iTeam) {
	int x,w,h,i,x1,y1,w1,h1,step;
	vec4_t color = { 1,1,0,1 };
	
	
	w = BOTS_HUD_PANEL_WIDTH;
	h = BOTS_HUD_ICON_SIZE*2;
	x = 640 - ( w + BOTS_HUD_PANEL_MARGIN );
	// y += +BOTS_HUD_PANEL_MARGIN;
	myCG_DrawPic(x,y, w, h, cgs.media.botsHUDiconsOther[generic_captain+iClass-1]);
	
	w1		= 0.75f * BOTS_HUD_ICON_SIZE;
	h1		= 1.5f  * BOTS_HUD_ICON_SIZE;
	step	= 0.3f * w1;
	x1 = x + BOTS_HUD_PANEL_WIDTH - w1 + (w1*0.5f) - (iLevel * step);
	y1 = y + h - h1; // + (h1*0.5f);
	trap_R_SetColor(color);
	for (i=0; i<iLevel; i++) {
		myCG_DrawPic(x1,y1, w1, h1, cgs.media.botsHUDiconsOther[generic_chevron1]);
		x1 += step;
	}
	trap_R_SetColor(NULL);
	y += h;
	
	return y;
}

// Draw a class icon and level
float BOTS_HUD_drawClassIcon(float y, int size, int iClass, int iLevel, int iTeam) {
	qhandle_t	*icon;
	
	icon = &cgs.media.botsHUDClassesIcons[iClass-1][iLevel][iTeam-1];
	// Try to load it if not already loaded
	if ( *icon == 0)
		*icon = BOTS_HUD_registerClassIcon(iClass,iLevel,iTeam);
	if (*icon != 0) {
		const int size = BOTS_HUD_PANEL_WIDTH;
		CG_DrawPic(640-size-BOTS_HUD_PANEL_MARGIN,y+BOTS_HUD_PANEL_MARGIN,size,size,*icon);
		y += size + BOTS_HUD_PANEL_MARGIN*2;
	}

	return y;
}

// Draws a head + a label for the class name
float BOTS_HUD_drawClassInfo(int y, int iClient, int iClass) {
	const int
		w = BOTS_HUD_PANEL_WIDTH,
		x = 640 - w - BOTS_HUD_PANEL_MARGIN;
	clientInfo_t	*ci;
	vec4_t			*tcolor;
	vec3_t	
		*clientAngles,
		angles;
	
	// Try to get the team we appear to be in
	ci = &cgs.clientinfo[iClient];

	if (iClass == -1)
		iClass = ci->classtype; // For the bg protection mainly

	switch (ci->modelName[0]) {
	case 'm':
	case 'M':
		tcolor	= BOTS_HUD_getTeamColor(TEAM_RED);
		break;
		
	case 'F':
	case 'f':
		tcolor	= BOTS_HUD_getTeamColor(TEAM_BLUE);
		break;
	default:
		tcolor	= BOTS_HUD_getTeamColor(0);
		break;
	}
	if (cg_draw3dIcons.integer) {
		// Draw a background if it's a 3D model
		CG_FillRect( x, y, w, w, (*tcolor) );
	}
	// Rotate it a bit (follow player's movement)
	if (iClient == cg.snap->ps.clientNum) {
		clientAngles = &cg.predictedPlayerEntity.lerpAngles;
	}
	else
		clientAngles = &cg_entities[iClient].lerpAngles;

	angles[0] = (*clientAngles)[0]; angles[2] = (*clientAngles)[2];
	angles[1] = 180 + 20.0f*cos((2*2*M_PI*abs((*clientAngles)[1]))/360.0f);
	CG_DrawHead(x, y, w, w, iClient, angles );
	y += w;
	
	// Draw the class name we're disguised into
	
	CG_FillRect( x, y, w, BOTS_HUD_ICON_SIZE, (*tcolor) );
	myCG_DrawPic(x,y,w,BOTS_HUD_ICON_SIZE,cgs.media.botsHUDiconsOther[generic_captain+iClass-1]);
	y += BOTS_HUD_ICON_SIZE + BOTS_HUD_PANEL_MARGIN;
	
	return y;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ID widgets revisited
void BOTS_DrawField (int x, int y, int width, int value) {
	char	num[16], *ptr;
	int		l;
	int		frame;
	vec4_t	color = { 0,0,0,1 };


	if ( width < 1 ) {
		return;
	}

	// draw number string
	if ( width > 5 ) {
		width = 5;
	}

	switch ( width ) {
	case 1:
		value = value > 9 ? 9 : value;
		value = value < 0 ? 0 : value;
		break;
	case 2:
		value = value > 99 ? 99 : value;
		value = value < -9 ? -9 : value;
		break;
	case 3:
		value = value > 999 ? 999 : value;
		value = value < -99 ? -99 : value;
		break;
	case 4:
		value = value > 9999 ? 9999 : value;
		value = value < -999 ? -999 : value;
		break;
	}

	Com_sprintf (num, sizeof(num), "%i", value);
	l = strlen(num);
	if (l > width)
		l = width;
	x += 2 + BOTS_HUD_FIELD_WIDTH*(width - l);

	ptr = num;
	while (*ptr && l)
	{
		if (*ptr == '-')
			frame = STAT_MINUS;
		else
			frame = *ptr -'0';

		trap_R_SetColor(color);
		CG_DrawPic( x+2,y+2, BOTS_HUD_FIELD_WIDTH, BOTS_HUD_FIELD_HEIGHT, cgs.media.numberShaders[frame] );
		trap_R_SetColor(NULL);
		CG_DrawPic( x,y, BOTS_HUD_FIELD_WIDTH, BOTS_HUD_FIELD_HEIGHT, cgs.media.numberShaders[frame] );

		x += BOTS_HUD_FIELD_WIDTH;
		ptr++;
		l--;
	}
}

// A bigger version (for the status bar)
void BOTS_DrawFieldBig(int x, int y, int width, int value, vec4_t hcolor) {
	char	num[16], *ptr;
	int		l;
	int		frame;
	vec4_t	color = { 0,0,0,1 };


	if ( width < 1 ) {
		return;
	}

	// draw number string
	if ( width > 5 ) {
		width = 5;
	}

	switch ( width ) {
	case 1:
		value = value > 9 ? 9 : value;
		value = value < 0 ? 0 : value;
		break;
	case 2:
		value = value > 99 ? 99 : value;
		value = value < -9 ? -9 : value;
		break;
	case 3:
		value = value > 999 ? 999 : value;
		value = value < -99 ? -99 : value;
		break;
	case 4:
		value = value > 9999 ? 9999 : value;
		value = value < -999 ? -999 : value;
		break;
	}

	Com_sprintf (num, sizeof(num), "%i", value);
	l = strlen(num);
	if (l > width)
		l = width;
	x += 2 + BOTS_HUD_FIELD_BIG_WIDTH*(width - l);

	ptr = num;
	while (*ptr && l)
	{
		if (*ptr == '-')
			frame = STAT_MINUS;
		else
			frame = *ptr -'0';

		trap_R_SetColor(color);
		CG_DrawPic( x+2,y+2, BOTS_HUD_FIELD_BIG_WIDTH, BOTS_HUD_FIELD_BIG_HEIGHT, cgs.media.numberShaders[frame] );
		trap_R_SetColor(hcolor);
		CG_DrawPic( x,y, BOTS_HUD_FIELD_BIG_WIDTH, BOTS_HUD_FIELD_BIG_HEIGHT, cgs.media.numberShaders[frame] );
		trap_R_SetColor(NULL);

		x += BOTS_HUD_FIELD_BIG_WIDTH;
		ptr++;
		l--;
	}
}

float BOTS_newDraw_Health(int y) {
	vec3_t	angles;
	vec3_t	origin;
	int		value;
	gitem_t *item; 


	y -= BOTS_HUD_FIELD_HEIGHT;

	value = cg.snap->ps.stats[STAT_HEALTH];
	if ( value > 75 ) {
		item = BG_FindItem("5 Health");
		trap_R_SetColor( colors[0] );		// white
	} else if (value > 25) {
		item = BG_FindItem("25 Health");
		trap_R_SetColor( colors[0] );	// green
	} else if (value > 0) {
		int			color;


		color = (cg.time >> 8) & 1;	// flash
		if (color)
			item = BG_FindItem("25 Health");
		else
			item = BG_FindItem("50 Health");

		trap_R_SetColor( colors[color] );
	} else {
		item = BG_FindItem("50 Health");
		trap_R_SetColor( colors[1] );	// red
	}

	// stretch the health up when taking damage
	BOTS_DrawField( 0, y, 3, value);
	trap_R_SetColor( NULL );

	if (cg_draw3dIcons.integer) {
		// 3D icon
		origin[0] = 90;
		origin[1] = 0;
		origin[2] = -10;
		
		VectorClear( angles );
		angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
		CG_Draw3DModel( CHAR_WIDTH*3, y - 20, ICON_SIZE+15, ICON_SIZE+15,
			cgs.media.healthModelSphere, 0, origin, angles );
		CG_Draw3DModel( CHAR_WIDTH*3, y - 20, ICON_SIZE+15, ICON_SIZE+15,
			cgs.media.healthModelCross, 0, origin, angles );
	}
	else {
		if (item)
			CG_DrawPic( BOTS_HUD_FIELD_WIDTH*3 + BOTS_HUD_FIELD_MARGIN, y, BOTS_HUD_FIELD_HEIGHT, BOTS_HUD_FIELD_HEIGHT, cg_items[ITEM_INDEX(item)].icon );
	}



	return y;
}

float BOTS_newDraw_Armor(int y) {
	vec3_t	angles;
	vec3_t	origin;
	int		value;

	y -= BOTS_HUD_FIELD_HEIGHT;

	value = cg.snap->ps.stats[STAT_ARMOR];
	trap_R_SetColor( colors[0] );
	BOTS_DrawField(0, y, 3, value);
	trap_R_SetColor( NULL );

	if (cg_draw3dIcons.integer) {
		// 3D icon
		origin[0] = 90;
		origin[1] = 0;
		origin[2] = -10;
		
		VectorClear( angles );
		angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0;
		CG_Draw3DModel( CHAR_WIDTH*3 + TEXT_ICON_SPACE, y, ICON_SIZE, ICON_SIZE,
			cgs.media.armorModel, 0, origin, angles );
	}
	else 
		//tbp: i want 2D icons if i say so! ;)
		CG_DrawPic( BOTS_HUD_FIELD_WIDTH*3 + BOTS_HUD_FIELD_MARGIN, y, BOTS_HUD_FIELD_HEIGHT, BOTS_HUD_FIELD_HEIGHT, cgs.media.armorIcon );


	return y;
}
void BOTS_DrawStatusBarHead( float x ) {
	vec3_t		angles;
	float		size, stretch;
	float		frac;

	VectorClear( angles );

	if ( !cg.bIsPoisonned && cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) {
		frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME;
		size = BOTS_HUD_BIG_ICONSIZE * 1.25 * ( 1.5 - frac * 0.5 );

		stretch = size - BOTS_HUD_BIG_ICONSIZE * 1.25;
		// kick in the direction of damage
		x -= stretch * 0.5 + cg.damageX * stretch * 0.5;

		cg.headStartYaw = 180 + cg.damageX * 45;

		cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
		cg.headEndPitch = 5 * cos( crandom()*M_PI );

		cg.headStartTime = cg.time;
		cg.headEndTime = cg.time + 100 + random() * 2000;
	} else {
		if ( cg.time >= cg.headEndTime ) {
			// select a new head angle
			cg.headStartYaw = cg.headEndYaw;
			cg.headStartPitch = cg.headEndPitch;
			cg.headStartTime = cg.headEndTime;
			cg.headEndTime = cg.time + 100 + random() * 2000;

			cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI );
			cg.headEndPitch = 5 * cos( crandom()*M_PI );
		}

		size = BOTS_HUD_BIG_ICONSIZE * 1.25;
	}

	// if the server was frozen for a while we may have a bad head start time
	if ( cg.headStartTime > cg.time ) {
		cg.headStartTime = cg.time;
	}

	frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime );
	frac = frac * frac * ( 3 - 2 * frac );
	angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac;
	angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac;

	CG_DrawHead( x, 480 - size, size, size, 
				cg.snap->ps.clientNum, angles );
}


int BOTS_DrawPickupItem( int y ) {
	int		value;
	float	*fadeColor;

// BEGIN bots - nits
	// int x = CHAR_WIDTH*3 + TEXT_ICON_SPACE + 50;
	int x = 0;
// END bots - nits

	if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) {
		return y;
	}

	y -= ICON_SIZE;

	value = cg.itemPickup;
	if ( value ) {
		fadeColor = CG_FadeColor( cg.itemPickupTime, 3000 );
		if ( fadeColor ) {
			CG_RegisterItemVisuals( value );
			trap_R_SetColor( fadeColor );   
// BEGIN bots - nits
			CG_DrawPic( x, y, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon );
			CG_DrawBigString( x + ICON_SIZE + 16, y + (ICON_SIZE/2 - BIGCHAR_HEIGHT/2), bg_itemlist[ value ].pickup_name, fadeColor[0] );
// END bots - nits
			trap_R_SetColor( NULL );
		}
	}
	
	return y;
}

void BOTS_DrawStatusBarFlag( float x, float y, int team ) {
	qhandle_t		cm;
	float			len;
	vec3_t			origin, angles;
	vec3_t			mins, maxs;
	float
		w = BOTS_HUD_BIG_ICONSIZE,
		h = BOTS_HUD_BIG_ICONSIZE;
	const float 
		fBLINK_TIME = 750.0f,
		fBLINK_AMPLITUDE = TEXT_ICON_SPACE*5;
	float
		fBump = sin( ((cg.time%((int)fBLINK_TIME))/fBLINK_TIME)*2*M_PI ) * fBLINK_AMPLITUDE;

	/*
	if (fBump < 0)
			fBump = -fBump;
	*/

	x -= fBump/2.0f;
	y -= fBump/2.0f;
	w += fBump;
	h += fBump;

	if ( cg_draw3dIcons.integer ) {
		VectorClear( angles );

		cm = cgs.media.redFlagModel;

		// offset the origin y and z to center the flag
		trap_R_ModelBounds( cm, mins, maxs );

		origin[2] = -0.5 * ( mins[2] + maxs[2] );
		origin[1] = 0.5 * ( mins[1] + maxs[1] );

		// calculate distance so the flag nearly fills the box
		// assume heads are taller than wide
		len = 0.5 * ( maxs[2] - mins[2] );		
		origin[0] = len / 0.268;	// len / tan( fov/2 )

		angles[YAW] = 60 * sin( cg.time / 2000.0 );;

		CG_Draw3DModel( x, y, w, h, 
			team == TEAM_RED ? cgs.media.redFlagModel : cgs.media.blueFlagModel, 
			0, origin, angles );
	} else if ( cg_drawIcons.integer ) {
		gitem_t *item = BG_FindItemForPowerup( team == TEAM_RED ? PW_REDFLAG : PW_BLUEFLAG );

		CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon );
	}

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// On the fly registering

// Register shaders we need for the HUD (class icons)
qhandle_t BOTS_HUD_registerClassIcon(int iClass, int iLevel, int iTeam) {
	static char *s[9][2] = {
		"captain",		"fcaptain2",
		"bodyguard",	"fbodyguard",
		"sniper",		"fsniper",
		"soldier",		"fsoldier",
		"berzerker",	"fberzerker",
		"infiltrator",	"finfiltrator",
		"kamikazee",	"fkamikazee",
		"nurse",		"fnurse",
		"scientist",	"fscientist"
	};
	qhandle_t	icon;
	char		
		buf[MAX_QPATH],
		*path,
		*prefix;


	// Holy shit, nothing is normalized
	switch (iClass) {
	case BOTS_CAPTAIN:
		path = iTeam==TEAM_RED?"mcaptain":"fcaptain";
		break;
	case BOTS_SCIENTIST:
		path = iTeam==TEAM_RED?"mscientist":"fscientist";
		break;
	default:
		path = iTeam==TEAM_RED?"male":"female";
		break;
	}

	switch (iLevel) {
	default:
	case 0:
		prefix = "icon_";
		break;
	case 1:
		prefix = "icon_l1";
		break;
	case 2:
		prefix = "icon_l2";
		break;
	case 3:
		prefix = "icon_l3";
		break;
	case 4:
		prefix = "icon_l4";
		break;
	}
		
	Com_sprintf(buf,MAX_QPATH,"models/players/%s/%s%s.tga",path,prefix,s[iClass-1][iTeam-1]);
	icon = trap_R_RegisterShaderNoMip(buf);
	if (icon == 0) {
		CG_Printf("BOTS_registerHUDClassIcon: can't load [%s]\n",buf);
	}
	return icon; // to be archived in cgs.media.botsHUDClassesIcons[9][4][2]
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Init time
void BOTS_registerHUDicons() {
	// Team stuff
	cgs.media.botsHUDiconsTeam[0][0] = trap_R_RegisterShaderNoMip("sprites/hud/switch_off_red.tga");
	cgs.media.botsHUDiconsTeam[1][0] = trap_R_RegisterShaderNoMip("sprites/hud/switch_on_red.tga");
	cgs.media.botsHUDiconsTeam[0][1] = trap_R_RegisterShaderNoMip("sprites/hud/switch_off_blue.tga");
	cgs.media.botsHUDiconsTeam[1][1] = trap_R_RegisterShaderNoMip("sprites/hud/switch_on_blue.tga");

	cgs.media.botsHUDiconsTeam[2][0] = trap_R_RegisterShaderNoMip("sprites/hud/label_promo_red.tga");
	cgs.media.botsHUDiconsTeam[3][0] = trap_R_RegisterShaderNoMip("sprites/hud/label_tech_red.tga");
	cgs.media.botsHUDiconsTeam[2][1] = trap_R_RegisterShaderNoMip("sprites/hud/label_promo_blue.tga");
	cgs.media.botsHUDiconsTeam[3][1] = trap_R_RegisterShaderNoMip("sprites/hud/label_tech_blue.tga");

	cgs.media.botsHUDiconsTeam[4][0] = trap_R_RegisterShaderNoMip("sprites/hud/frame_red.tga");
	cgs.media.botsHUDiconsTeam[4][1] = trap_R_RegisterShaderNoMip("sprites/hud/frame_blue.tga");

	// Use the generated code
	BOTS_registerHUDiconsother(&cgs.media.botsHUDiconsOther[reserved9+1]);
	cgs.media.botsHUDiconsOther[reserved0] = trap_R_RegisterShaderNoMip("sprites/hud/icon_cloak.tga");
	cgs.media.botsHUDiconsOther[reserved1] = trap_R_RegisterShaderNoMip("sprites/hud/icon_moving.tga");
	cgs.media.botsHUDiconsOther[reserved2] = trap_R_RegisterShaderNoMip("sprites/hud/icon_lightbulb.tga");
	cgs.media.botsHUDiconsOther[reserved3] = trap_R_RegisterShaderNoMip("sprites/hud/icon_flake.tga");
	cgs.media.botsHUDiconsOther[reserved4] = trap_R_RegisterShaderNoMip("sprites/hud/icon_thumbup.tga");
	cgs.media.botsHUDiconsOther[reserved5] = trap_R_RegisterShaderNoMip("sprites/hud/icon_key.tga");


	CG_Printf("...BOTS_registerHUDicons: %i icons loaded\n",MAX_HUD_ICONS_OTHER);
}

// THIS IS SOME AUTOMATICALLY GENERATED CODE, DON'T MODIFY PLEASE
// ./codegen.pl: Sat Sep 23 05:22:23 CEST 2000
void BOTS_registerHUDiconsother(qhandle_t *p) {
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/number_0.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/number_1.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/number_2.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/number_3.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/number_4.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/number_5.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/number_6.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/number_7.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/number_8.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/number_9.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/grenade_proxy.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/grenade_decoy.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/grenade_nuke.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/grenade_flash.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/grenade_tele.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_ready.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_normal.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_split.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_split1.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_split2.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_split3.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_key.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_minus.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_chevron1.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_chevron2.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_captain.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_bodyguard.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_sniper.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_soldier.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_berzerker.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_infiltrator.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_kamikazee.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_nurse.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/generic_scientist.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/kami_cluster.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/kami_detmode.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/kami_autorewire.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/kami_longrange.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/kami_sticky.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/soldier_conquer.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/soldier_tag.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/soldier_guided.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/nurse_poison.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/infiltrator_disguise.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/infiltrator_steal.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/sniper_visibility.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/sniper_sight.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/sniper_cloakwalk.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/bodyguard_laser.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/bodyguard_pulse.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/bodyguard_protection.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/bodyguard_decoy.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/berzerker_autoquad.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/berzerker_autocharge.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/berzerker_parasites.tga");
	 *(p++) = trap_R_RegisterShaderNoMip("sprites/hud/captain_warcry.tga");
}
